/*
 * @Author: 0x9DEFA478
 * @Date: 2024-11-25 14:20:12
 * @LastEditTime: 2025-09-15 23:47:05
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * 
 * 
 */
#include "SystemProcessLinux.hpp"
#ifdef __linux__
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <stdexcept>
#include <sstream>
#include <list>




// static bool SetBlock(int fd,bool IsBlock){
//   auto flags=fcntl(fd,F_GETFL,0);
  
//   if(flags==-1){
//     return false;
//   }
  
//   auto flags_new=flags;

//   if(IsBlock){
//     flags_new&=~O_NONBLOCK;
//   }else{
//     flags_new|=O_NONBLOCK;
//   }

//   if(flags==flags_new){
//     return true;
//   }

//   if(fcntl(fd,F_SETFL,flags_new)==(-1)){
//     return false;
//   }

//   return true;
// }

static std::string cmd_args_toString(char* const* cmd_args){
  std::stringstream ss;
  while(cmd_args!=nullptr){
    ss<<*cmd_args;
  }
  return ss.str();
}




class Linux_Pipe{

  public:
    Linux_Pipe();
    ~Linux_Pipe();

    int Pipe_Read()const{return pipe_Read;}
    int Pipe_Write()const{return pipe_Write;}

    void CloseRead();
    void CloseWrite();

  private:
    int pipe_Read;
    int pipe_Write;
};

Linux_Pipe::Linux_Pipe(){

  int pipelist[2];
  auto r=pipe(pipelist);
  if(r==-1){
    throw std::runtime_error("Linux匿名管道创建失败:"+std::string(strerror(errno)));
  }

  pipe_Read=pipelist[0];
  pipe_Write=pipelist[1];
}

Linux_Pipe::~Linux_Pipe(){
  CloseRead();
  CloseWrite();
}

void Linux_Pipe::CloseRead(){
  if(pipe_Read<0){
    return;
  }
  close(pipe_Read);
  pipe_Read=-1;
}
void Linux_Pipe::CloseWrite(){
  if(pipe_Write<0){
    return;
  }
  close(pipe_Write);
  pipe_Write=-1;
}


struct SystemProcessLinux_Instance{
  Linux_Pipe Output;
  Linux_Pipe Input;
  int pid;
  bool pipeIO;
  bool outputIsStop;
  bool inputIsStop;
  bool isStop;
  int Result;

  H::Pointer<char>::Const Cache;

  SystemProcessLinux_Instance(char* const* cmd_args,bool pipeIO);
  ~SystemProcessLinux_Instance();
  
  H::Pointer<char> Read();
  bool Write(const void* Buffer,int Length);
  bool IsStop();
  void WaitStop();
  void Stop();
};

SystemProcessLinux_Instance::SystemProcessLinux_Instance(char* const* cmd_args,bool pipeIO):pipeIO(pipeIO),outputIsStop(false),inputIsStop(false),isStop(false),Result(-1){
  
  auto pid=fork();
  if(pid<0){
    throw std::runtime_error("Windows进程创建失败 目标命令: "+ cmd_args_toString(cmd_args) +" 错误: "+std::string(strerror(errno)));
  }
  if(pid==0){
    Input.CloseWrite();
    Output.CloseRead();
    if(pipeIO){
      if(STDIN_FILENO!=dup2(Input.Pipe_Read(),STDIN_FILENO)){
        exit(-1);
      }
      if(STDOUT_FILENO!=dup2(Output.Pipe_Write(),STDOUT_FILENO)){
        exit(-1);
      }
      if(STDERR_FILENO!=dup2(Output.Pipe_Write(),STDERR_FILENO)){
        exit(-1);
      }
    }
    exit(execvp(cmd_args[0],&cmd_args[0]));
    for(;;){
    }
  }
  this->pid=pid;

  Output.CloseWrite();
  Input.CloseRead();
}

SystemProcessLinux_Instance::~SystemProcessLinux_Instance(){
  if(!IsStop()){
    kill(pid,0);
  }
}

H::Pointer<char> SystemProcessLinux_Instance::Read(){
  int readLength;

  if(outputIsStop||(!pipeIO)){
    return H::Pointer<char>();
  }

  auto buffer=H::Pointer<char>::Array(1024);
  readLength=read(Output.Pipe_Read(),buffer,buffer.Length());
  if(readLength<1){
    outputIsStop=true;
    return H::Pointer<char>();
  }

  return buffer.Clone(readLength);
}

bool SystemProcessLinux_Instance::Write(const void* Buffer,int Length){

  if(inputIsStop||(!pipeIO)){
    return false;
  }

  if(write(Input.Pipe_Write(),Buffer,Length)==(ssize_t)Length){
    inputIsStop=true;
    return false;
  }

  return true;
}

bool SystemProcessLinux_Instance::IsStop(){
  if(isStop){
    return true;
  }

  if(pid==waitpid(pid,&Result,WNOHANG)){
    isStop=true;
    return true;
  }

  return false;
}

void SystemProcessLinux_Instance::WaitStop(){
  if(isStop){
    return;
  }

  while(pid!=waitpid(pid,&Result,0)){}
  isStop=true;
}

void SystemProcessLinux_Instance::Stop(){
  if(isStop){
    return;
  }
  kill(pid,SIGKILL);
  while(pid!=waitpid(pid,&Result,0)){}
  isStop=true;
}




SystemProcessLinux::SystemProcessLinux():Instance(nullptr){}

SystemProcessLinux::~SystemProcessLinux(){
  SystemProcessLinux_Instance* Instance;

  Instance=static_cast<SystemProcessLinux_Instance*>(this->Instance);

  if(Instance==nullptr){
    return;
  }

  delete Instance;
}

void SystemProcessLinux::Run(const H::Pointer<std::string>::Const& Command,bool pipeIO){
  
  auto commandBuffers=H::Pointer<H::Pointer<char>>::Array(Command.Length()+1);
  auto command=H::Pointer<char*>::Array(Command.Length()+1);
  SystemProcessLinux_Instance* Instance;

  if(this->Instance!=nullptr){
    throw std::runtime_error("SystemProcessLinux对象不能重复Run");
  }

  for(std::size_t i=0,count=Command.Length();i<count;i++){
    auto length=Command[i].length();
    commandBuffers[i]=H::Pointer<char>::Array(length+1);
    for(std::size_t j=0;j<length;j++){
      commandBuffers[i][j]=Command[i][j];
    }
    commandBuffers[i][length]='\0';

    command[i]=commandBuffers[i];
  }
  command[command.Length()-1]=nullptr;

  Instance=new SystemProcessLinux_Instance(command,pipeIO);
  this->Instance=static_cast<void*>(Instance);
}

bool SystemProcessLinux::WriteInput(const std::string& str){
  SystemProcessLinux_Instance* Instance;

  Instance=static_cast<SystemProcessLinux_Instance*>(this->Instance);

  if(Instance==nullptr){
    return false;
  }

  return Instance->Write(str.c_str(),str.length());
}

H::Pointer<char> SystemProcessLinux::ReadOutput(){
  SystemProcessLinux_Instance* Instance;

  Instance=static_cast<SystemProcessLinux_Instance*>(this->Instance);

  if(Instance==nullptr){
    return H::Pointer<char>();
  }

  if(Instance->Cache){
    auto r=Instance->Cache.Clone();
    Instance->Cache.Set_nullptr();
    return r;
  }

  return Instance->Read();
}

std::string SystemProcessLinux::ReadLine(char SplitChar){
  SystemProcessLinux_Instance* Instance;

  Instance=static_cast<SystemProcessLinux_Instance*>(this->Instance);

  if(Instance==nullptr){
    return "";
  }

  for(;;){
    auto& s=Instance->Cache;
    auto len=s.Length();
    for(H::usize SplitIndex=0;SplitIndex<len;SplitIndex++){
      if(s[SplitIndex]==SplitChar){
        std::string r=std::string(s.GetPointer(),0,SplitIndex);

        if(len>(SplitIndex+1)){
          auto length=len-(SplitIndex+1);
          auto newCache=H::Pointer<char>::Array(length);
          for(H::usize i=0;i<length;i++){
            newCache[i]=s[i+SplitIndex+1];
          }
          Instance->Cache=newCache;
        }else{
          Instance->Cache.Set_nullptr();
        }

        return r;
      }
    }
    auto data=Instance->Read();
    if(!data){
      return "";
    }
    if(Instance->Cache){
      auto beginIndex=Instance->Cache.Length();
      auto length=Instance->Cache.Length();
      auto newCache=Instance->Cache.Clone(Instance->Cache.Length()+data.Length());
      
      for(H::usize i=0;i<length;i++){
        newCache[beginIndex+i]=data[i];
      }

      Instance->Cache=newCache;
    }else{
      Instance->Cache=data;
    }
  }

}

bool SystemProcessLinux::IsStop(){
  SystemProcessLinux_Instance* Instance;

  Instance=static_cast<SystemProcessLinux_Instance*>(this->Instance);

  if(Instance==nullptr){
    return true;
  }

  return Instance->IsStop();
}

void SystemProcessLinux::WaitStop(){
  SystemProcessLinux_Instance* Instance;

  Instance=static_cast<SystemProcessLinux_Instance*>(this->Instance);

  if(Instance==nullptr){
    return;
  }

  std::list<H::Pointer<char>> dataList;
  H::usize Length=0;
  for(;;){
    auto data=Instance->Read();
    if(!data){
      break;
    }
    dataList.emplace_back(data);
    Length+=data.Length();
  }

  H::usize index=Instance->Cache.Length();
  auto newCache=Instance->Cache.Clone(index+Length);
  for(auto& Item:dataList){
    for(auto c:Item){
      newCache[index++]=c;
    }
  }
  Instance->Cache=newCache;

  Instance->WaitStop();
}

void SystemProcessLinux::Stop(){
  SystemProcessLinux_Instance* Instance;

  Instance=static_cast<SystemProcessLinux_Instance*>(this->Instance);

  if(Instance==nullptr){
    return;
  }

  Instance->Stop();

}

int SystemProcessLinux::GetResult(){
  SystemProcessLinux_Instance* Instance;

  Instance=static_cast<SystemProcessLinux_Instance*>(this->Instance);

  if(Instance==nullptr){
    return -1;
  }

  return Instance->Result;
}




#endif



